#include "user.h"
//#define TM_DBG DBG_INFO
#define TM_DBG(X, Y...)
Timer_CtrlStruct TimerCtrl;
void Timer_GetTimeFromPoweron(uint32_t *Sec, uint32_t *Msec)
{
	*Sec = TimerCtrl.Sec;
	*Msec = TimerCtrl.Msec;
}

void Timer_Init(void)
{
	SysTick_Config(SystemCoreClock/SYS_TICK_BASE);
	TimerCtrl.Head = NULL;
}

void Timer_Task(PV_Union Param)
{
	Timer_t *Timer = TimerCtrl.Head;
	if (!TimerCtrl.Irq)
		return ;

	TimerCtrl.Irq = 0;
	while (Timer)
	{
		if (Timer->Work)
		{
			if (TimerCtrl.Sec >= Timer->TargetSec)
			{
				if (TimerCtrl.Msec >= Timer->TargetMsec)
				{
					Timer->Work = 0;
					if (Timer->CallBack)
					{
						Timer->CallBack(Timer->Param);
					}
					else
					{
						Timer->ToFlag = 1;
					}
					if (!Timer->Work)
					{
						if (Timer->AddSec || Timer->AddMsec)
						{
							Timer->TargetSec += Timer->AddSec;
							Timer->TargetMsec += Timer->AddMsec;
							if (Timer->TargetMsec >= 1000)
							{
								Timer->TargetSec += (Timer->TargetMsec / 1000);
								Timer->TargetMsec = Timer->TargetMsec % 1000;
							}
							Timer->Work = 1;
							TM_DBG("timer %d reload %u %u", Timer->ID, Timer->TargetSec, Timer->TargetMsec);
						}
						else
						{
							TM_DBG("timer %d stop", Timer->ID);
						}
					}

				}
			}
		}
		Timer = Timer->Next;
	}
}

void Timer_Run(void)
{
	PV_Union Param;
	Timer_Task(Param);
}

int Timer_Register(Timer_t *Timer, MyCBFun_t CB, void *Param)
{
	Timer_t *Head = TimerCtrl.Head;
	Timer->Next = NULL;
	Timer->CallBack = CB;
	Timer->Param.p = Param;
	Timer->ID = TimerCtrl.IDSn;
	TimerCtrl.IDSn++;

	if (TimerCtrl.Head)
	{
		TimerCtrl.Head = Timer;
		Timer->Next = Head;
	}
	else
	{
		TimerCtrl.Head = Timer;
	}
	TM_DBG("timer %d register", Timer->ID);
	return 0;
}

int Timer_Start(Timer_t *Timer, uint32_t ToSec, uint32_t ToMsec, uint8_t IsRepeat)
{
	if (IsRepeat)
	{
		Timer->AddSec = ToSec + (ToMsec / 1000);
		Timer->AddMsec = (ToMsec % 1000);
	}

	Timer->TargetSec = TimerCtrl.Sec + ToSec;
	Timer->TargetMsec = TimerCtrl.Msec + ToMsec;
	Timer->TargetSec += Timer->TargetMsec / 1000;
	Timer->TargetMsec = Timer->TargetMsec % 1000;
	Timer->Work = 1;
	Timer->ToFlag = 0;
	TM_DBG("timer %d start %u %u", Timer->ID, Timer->TargetSec, Timer->TargetMsec);
	return 0;
}

void Timer_Switch(Timer_t *Timer, uint8_t OnOff)
{
	Timer->Work = OnOff;
}

void Timer_Restart(Timer_t *Timer, uint32_t ToSec, uint32_t ToMsec)
{
	Timer->TargetSec = TimerCtrl.Sec + ToSec;
	Timer->TargetMsec = TimerCtrl.Msec + ToMsec;
	Timer->TargetSec += Timer->TargetMsec / 1000;
	Timer->TargetMsec = Timer->TargetMsec % 1000;
	Timer->Work = 1;
	Timer->ToFlag = 0;
	TM_DBG("timer %d restart %u %u", Timer->ID, Timer->TargetSec, Timer->TargetMsec);
}

void Timer_Del(Timer_t *Timer)
{
	Timer_t *Cur = TimerCtrl.Head;
	if (TimerCtrl.Head == Timer)
	{
		Cur = TimerCtrl.Head->Next;
		TimerCtrl.Head = Cur;
		TM_DBG("timer %d del in head %x", Timer->ID, TimerCtrl.Head);
		return ;
	}
	while ( (Cur->Next != Timer) && Cur->Next )
	{
		Cur = Cur->Next;
	}
	if (Cur->Next != Timer)
	{
		TM_DBG("timer %d no exsit", Timer->ID);
		return ;
	}
	Cur = Cur->Next->Next;
	TM_DBG("timer %d del", Timer->ID);
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
	TimerCtrl.Msec++;
	if (TimerCtrl.Msec >= 1000)
	{
		TimerCtrl.Sec++;
		TimerCtrl.Msec -= 1000;
	}
	TimerCtrl.Irq = 1;
}
